//==============================================================================
// HashSampleSearchEngine.hh
// ----------------------------------------------------------------------------
// A sample search engine based on hash 
//
//------------------------------------------------------------------------------
// $Id: $
//------------------------------------------------------------------------------
// $Log: $
//
//==============================================================================
//.......1.........2.........3.........4.........5.........6.........7.........8
//

#include "LocalSTL.hh"
#include <map>
#include "SequenceHash.hh"
#include "SeqSampler.hh"


#ifndef _HASH_SAMPLE_SEARCH_ENGINE
#define _HASH_SAMPLE_SEARCH_ENGINE

//------------------------------------------------------------------------------
// * SampleInfo
//------------------------------------------------------------------------------
// A structure to contain the data portion of the key-data part of a hash_map. 
// Actually, an index into a vector of these structures is actually stored in the 
// hash_map, so this is kept as a parallel data structure:
//
// 
// 
class SampleInfo{
public:
  vector<int> mLocations;
  vector<int> mSourceIdx;
  //Sequence mSequence;
  
  void AddHit(int i,int seqIdx){
	 mLocations.push_back(i);
	 mSourceIdx.push_back(seqIdx);
  };

  void Print(ostream &fout){
	 for(int i = 0;i< mLocations.size();i++){
		fout<<"\t"<<mLocations[i]<<endl;
	 }
  };
};

//------------------------------------------------------------------------------
// * SampleSearchResult
//------------------------------------------------------------------------------
//
class SampleSearchResult{
public:
  // KJD This is a lot of space to take up for each search result, but it simplifies
  // a lot, I think. 
  long mSourceIdx;
  long mQueryIdx;
  long mSampleIdx;

  long mSampleLoc;
  long mSourceLoc;

  void Print(ostream &fout){
	 fout<<mSourceIdx<<"\t"<<mQueryIdx<<"\t"<<mSampleIdx<<"\t"<<mSampleLoc<<"\t"<<mSourceLoc<<endl;
  }

  bool operator==(SampleSearchResult &a){
	 SampleSearchResult &b = (*this);
	 if ((a.mSampleLoc == b.mSampleLoc) && (a.mSourceLoc == b.mSourceLoc)) return(true);
	 else return(false);
  }

};

class SampleSearchResultVec : public vector<SampleSearchResult>{
public:

  void Print(ostream &fout){
	 for(int i = 0;i< size();i++){
		(*this)[i].Print(fout);
	 }
  }

  void SortBySourceLoc();
  void SortBySourceIdx();
};


//------------------------------------------------------------------------------
// * HashSampleSearchEngine
//------------------------------------------------------------------------------
// Creates a hash_map of all the n-mers in a source sequence.  Query sequences
// are sampled and searched against this hash_map to yeild a set of exact query 
// hits, which can then be post-processed to yeild information about Query-Source
// relationships. 
// 
// 
class HashSampleSearchEngine{
public:
  int                  mSampleSize;     // Size of samples in bp. 
  int                  mSampleDensity;  // Density of samples in Samples/Kbp
  SequenceHashMap      mMap;            // Map for the sequence 
  vector<SampleInfo>   mHashInfo;       // Info about each map entry. 

  long mMaxLocsPerMer;
  long mbugMaxLocsCount;

  // Index to keep track of which sequences have been added to the hash. 
  int  mSeqIdx; 

  // Debug and performance testing variables
  long mTotalSamples;
  long mBucketSize;

  HashSampleSearchEngine(){

	 mSeqIdx = 0;

	 mBucketSize=50000;mTotalSamples=0;mSampleSize=25;mSampleDensity=4;
	 mMaxLocsPerMer = 50000000;
	 mbugMaxLocsCount=0;};

  HashSampleSearchEngine(int size,int density){
	 mSampleSize=size;
	 mBucketSize = 50000;
	 mSampleDensity=density;
	 mTotalSamples = 0; // for performance testing
	 mMaxLocsPerMer = 50000000;
	 mbugMaxLocsCount = 0;
  };

  void Add(Sequence &Seq,int seqIdx);
  void Create(Sequence &Seq);
  void Create(SequenceVector &SeqVec,int start,int end);
  void SampleQuery(Sequence &QueryIn,SequenceVector &SamplesOut);
  long Search(Sequence &Query,SampleSearchResultVec &Results);
  long SearchRev(Sequence &Query,SampleSearchResultVec &Results);

  long Search(SequenceVector &Queries,SampleSearchResultVec &Results);
  long SearchRev(SequenceVector &Queries,SampleSearchResultVec &Results);

  long SearchWithSamples(SequenceVector &Samples,SampleSearchResultVec &Results);

  void SearchSingle(Sequence &Query,SampleSearchResultVec &Results);

};


#endif


